// https://www.acwing.com/problem/content/description/840/

#include <iostream>
#include <vector>

using namespace std;

/**
 * @brief 调整堆，使以 index 为根的子树满足最大堆性质
 *
 * @param arr 要调整的数组
 * @param n 堆的有效大小（数组长度）
 * @param index 当前需要调整的根节点索引
 *
 * @note 该函数递归地确保以 index 为根的子树满足最大堆性质
 */
void heapify(vector<int>& arr, int n, int index) {
    int largest = index;       // 假设当前根节点是最大值
    int left = 2 * index;  // 左子节点索引
    int right = 2 * index + 1; // 右子节点索引

    // 如果左子节点存在且比根节点大，则更新最大值索引
    if (left < n && arr[left] > arr[largest]) {
        largest = left;
    }

    // 如果右子节点存在且比当前最大值大，则更新最大值索引
    if (right < n && arr[right] > arr[largest]) {
        largest = right;
    }

    // 如果最大值不是根节点，则交换根节点与最大值，并递归调整受影响的子树
    if (largest != index) {
        swap(arr[index], arr[largest]); // 交换节点
        heapify(arr, n, largest);    // 递归调整子树
    }
}

/**
 * @brief  对输入数组进行堆排序
 *
 * @param arr  待排序数组
 *
 * @note  该函数使用最大堆进行排序，先构建最大堆，再进行排序
 */
void heapSort(vector<int>& arr) {
    const int n = arr.size();

    // 1. 构建最大堆（从最后一个非叶子节点开始调整）
    for (int i = n / 2; i > 0; i--) {
        heapify(arr, n, i);
    }

    // 2. 逐步将堆顶元素（最大值）交换到数组末尾，并调整堆
    for (int i = n; i > 1; i--) {
        swap(arr[1], arr[i]);       // 将当前最大值（堆顶）放到数组末尾
        heapify(arr, i, 1);   // 调整剩余部分为最大堆
    }
}

int main() {
    int m, n, t;
    scanf("%d%d", &m, &n);
    vector<int> nums(m+1);
    for (int i=1; i<=m; i++) {
        scanf("%d", &nums[i]);
    }
    heapSort(nums);
    for (int i = 1; i <= n; ++i) {
        cout<<nums[i]<<" ";
    }
    return 0;
}
